package org.example;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * 简单IOC容器实现，支持@Configuration和@Bean注解
 */
public class SimpleIOCContainer {
    // 存储Bean实例：key=bean名称，value=bean实例
    private final Map<String, Object> beanMap = new HashMap<>();

    /**
     * 构造函数，初始化容器并扫描指定包
     * @param basePackage 要扫描的基础包名（如：org.example）
     * @throws Exception 扫描或实例化过程中的异常
     */
    public SimpleIOCContainer(String basePackage) throws Exception {
        scanPackages(basePackage);
    }

    /**
     * 扫描指定包及其子包下的所有类
     */
    private void scanPackages(String basePackage) throws Exception {
        // 将包名转换为文件路径（如：org.example -> org/example）
        String packagePath = basePackage.replace(".", File.separator);
        Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(packagePath);

        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            File rootDir = new File(resource.toURI());
            if (rootDir.exists() && rootDir.isDirectory()) {
                scanClasses(rootDir, basePackage);
            }
        }
    }

    /**
     * 递归扫描目录下的所有类文件
     */
    private void scanClasses(File dir, String packageName) throws Exception {
        File[] files = dir.listFiles();
        if (files == null) return;

        for (File file : files) {
            if (file.isDirectory()) {
                // 递归扫描子目录
                scanClasses(file, packageName + "." + file.getName());
            } else if (file.getName().endsWith(".class")) {
                // 处理.class文件
                String className = packageName + "." + file.getName().replace(".class", "");
                Class<?> clazz = Class.forName(className);
                processConfigurationClass(clazz);
            }
        }
    }

    /**
     * 处理@Configuration注解的配置类
     */
    private void processConfigurationClass(Class<?> clazz) throws Exception {
        // 检查是否有@Configuration注解
        if (!clazz.isAnnotationPresent(Configuration.class)) {
            return;
        }

        // 实例化配置类（要求配置类有默认构造函数）
        Object configInstance = clazz.getDeclaredConstructor().newInstance();

        // 处理配置类中的@Bean方法
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(Bean.class)) {
                processBeanMethod(method, configInstance);
            }
        }
    }

    /**
     * 处理@Bean注解的方法，创建并注册Bean
     */
    private void processBeanMethod(Method method, Object configInstance) throws Exception {
        Bean beanAnnotation = method.getAnnotation(Bean.class);
        String beanName = beanAnnotation.value().trim();
        // 如果未指定bean名称，使用方法名作为默认名称
        if (beanName.isEmpty()) {
            beanName = method.getName();
        }

        // 调用@Bean方法获取Bean实例
        Object beanInstance = method.invoke(configInstance);

        // 注册Bean到容器
        if (beanMap.containsKey(beanName)) {
            throw new RuntimeException("Bean名称冲突：" + beanName);
        }
        beanMap.put(beanName, beanInstance);
    }

    /**
     * 根据名称获取Bean
     */
    public Object getBean(String beanName) {
        return beanMap.get(beanName);
    }

    /**
     * 根据类型获取Bean（只返回第一个匹配的Bean）
     */
    @SuppressWarnings("unchecked")
    public <T> T getBean(Class<T> requiredType) {
        for (Object bean : beanMap.values()) {
            if (requiredType.isInstance(bean)) {
                return (T) bean;
            }
        }
        return null;
    }

    /**
     * 获取容器中所有Bean的名称
     */
    public String[] getBeanDefinitionNames() {
        return beanMap.keySet().toArray(new String[0]);
    }
}
